Perlで2つの行区切り文字の間の行を抽出するにはどうすればよいですか?
質問
抽出したい内容のASCIIログファイルがあります。 Perlを適切に習得するのに時間がかかったことはありませんが、これはこのタスクに適したツールであると考えています。
ファイルは次のように構成されています:
... ... some garbage ... ... garbage START what i want is on different lines END ... ... more garbage ... next one START more stuff I want, again spread through multiple lines END ... more garbage
だから、各 START
と END
の区切り文字列の間の行を抽出する方法を探しています。
どうすればいいですか?
これまでのところ、 START
文字列を含む行を印刷する方法、または探しているものに多少関連するその他のドキュメント項目の例をいくつか見つけました。
解決
フリップフロップ演算子(範囲演算子と呼ばれる)が必要な場合 ..
#!/usr/bin/env perl
use strict;
use warnings;
while (<>) {
if (/START/../END/) {
next if /START/ || /END/;
print;
}
}
print
の呼び出しを、実際にやりたいことで置き換えます(たとえば、行を配列にプッシュし、編集し、フォーマットします)。私は実際に START
または END
がある行を next
-ingしていますが、その動作は望ましくないかもしれません。この演算子およびその他の説明については、この記事を参照してください。便利なPerl特殊変数。
他のヒント
perlfaq6 のそれ自体が異なる行にある2つのパターン間の行を引き出すにはどうすればよいですか
Perlのややエキゾチックな..演算子(perlopで文書化されています)を使用できます:
perl -ne 'print if /START/ .. /END/' file1 file2 ...
行ではなくテキストが必要な場合は、使用します
perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...
ただし、STARTからENDまでのネストされたオカレンスが必要な場合は、バランスの取れたテキストのマッチングに関するこのセクションの質問で説明されている問題に直面します。
.. :: pの別の使用例
while (<>) {
$in_header = 1 .. /^$/;
$in_body = /^$/ .. eof;
# now choose between them
} continue {
$. = 0 if eof; # fix $.
}
複数を取得するにはどうすればよいですかPerlの一致する行の後の行?
それはどう?その1つでは、END文字列は$ ^です。これをEND文字列に変更できます。
私は初心者でもありますが、そこにある解決策は多くの方法を提供します...上記のリンクとは違うことをもっと具体的に教えてください。
while (<>) {
chomp; # strip record separator
if(/END/) { $f=0;}
if (/START/) {
s/.*START//g;
$f=1;
}
print <*>
次回はいくつかのコードを書いてみてください
."\n" if $f;
}
次回はいくつかのコードを書いてみてください
Telemachusの返信後、物事が溢れ出しました。これは結局私が見ている解決策として機能します。
- 2つの文字列で区切られた行を抽出しようとしています行。これはTelemachusのソリューションでできます。
- 最初の行には削除したいスペースがあります。私も含めています。
- また、各行セットを個別のファイルに抽出しようとしています。
これは私にとってはうまくいきますが、コードはいものに分類できます。これは、私が現在、Perlの事実上の新人だからです。とにかくここに行きます:
#!/usr/bin/env perl
use strict;
use warnings;
my $start='CINFILE=
他の人にも役立つことを願っています。
乾杯。
;
my $stop='^#
他の人にも役立つことを願っています。
乾杯。
;
my $filename;
my $output;
my $counter=1;
my $found=0;
while (<>) {
if (/$start/../$stop/) {
$filename=sprintf("boletim_%06d.log",$counter);
open($output,'>>'.$filename) or die $!;
next if /$start/ || /$stop/;
if($found == 0) { print $output (split(/ /))[1]; }
else { print $output Telemachusの返信後、物事が溢れ出しました。これは結局私が見ている解決策として機能します。
- 2つの文字列で区切られた行を抽出しようとしています行。これはTelemachusのソリューションでできます。
- 最初の行には削除したいスペースがあります。私も含めています。
- また、各行セットを個別のファイルに抽出しようとしています。
これは私にとってはうまくいきますが、コードはいものに分類できます。これは、私が現在、Perlの事実上の新人だからです。とにかくここに行きます:
<*>
他の人にも役立つことを願っています。
乾杯。
; }
$found=1;
} else { if($found == 1) { close($output); $counter++; $found=0; } }
}
他の人にも役立つことを願っています。 乾杯。
「仮想の新人」から来るのは悪くない。できることの1つは、&quot; $ found = 1&quot; &quot; if($ found == 0)&quot;の内側$ startと$ stopの間で毎回その割り当てを行わないようにブロックします。
もう少しaいのは、私の意見では、$ start / $ stop-blockを入力するたびに同じファイルハンドラを開くことです。
これはそれを回避する方法を示しています:
#!/usr/bin/perl
use strict;
use warnings;
my $start='CINFILE=;
my $stop='^#;
my $filename;
my $output;
my $counter=1;
my $found=0;
while (<>) {
# Find block of lines to extract
if( /$start/../$stop/ ) {
# Start of block
if( /$start/ ) {
$filename=sprintf("boletim_%06d.log",$counter);
open($output,'>>'.$filename) or die $!;
}
# End of block
elsif ( /$end/ ) {
close($output);
$counter++;
$found = 0;
}
# Middle of block
else{
if($found == 0) {
print $output (split(/ /))[1];
$found=1;
}
else {
print $output 「仮想の新人」から来るのは悪くない。できることの1つは、&quot; $ found = 1&quot; &quot; if($ found == 0)&quot;の内側$ startと$ stopの間で毎回その割り当てを行わないようにブロックします。
もう少しaいのは、私の意見では、$ start / $ stop-blockを入力するたびに同じファイルハンドラを開くことです。
これはそれを回避する方法を示しています:
<*>;
}
}
}
# Find block of lines to extract
}